#include "videoplayer.h"

VideoPlayer::VideoPlayer(std::string _videoName)
{
	// initialize members for video
	mVideoNext = 0;
	mVideoFrame=0;											// Frame Counter

	mVideoHdc = CreateCompatibleDC(0);								// Creates A Compatible Device Context
	mVideoData = 0;										// Pointer To Our Resized Image

	

	std::wstring_convert< std::codecvt<wchar_t,char,std::mbstate_t> > conv ;
	mWStrVideoName = conv.from_bytes(_videoName) ;
	mVideoName = mWStrVideoName.c_str();
}

VideoPlayer::~VideoPlayer()
{
	Deinitialize();
}


void VideoPlayer::flipIt(void* buffer)										// Flips The Red And Blue Bytes (256x256)
{
	void* b = buffer;											// Pointer To The Buffer
	__asm														// Assembler Code To Follow
	{
		mov ecx, 1024*768										// Counter Set To Dimensions Of Our Memory Block
			mov ebx, b												// Points ebx To Our Data (b)
label:													// Label Used For Looping
		mov al,[ebx+0]										// Loads Value At ebx Into al
		mov ah,[ebx+2]										// Loads Value At ebx+2 Into ah
		mov [ebx+2],al										// Stores Value In al At ebx+2
			mov [ebx+0],ah										// Stores Value In ah At ebx

			add ebx,3											// Moves Through The Data By 3 Bytes
			dec ecx												// Decreases Our Loop Counter
			jnz label											// If Not Zero Jump Back To Label
	}
}

void VideoPlayer::OpenAVI(LPCWSTR szFile)										// Opens An AVI File (szFile)
{
	TCHAR	title[100];											// Will Hold The Modified Window Title

	AVIFileInit();												// Opens The AVIFile Library

	// Opens The AVI Stream
	if (AVIStreamOpenFromFile(&mVideoPavi, szFile, streamtypeVIDEO, 0, OF_READ, NULL) !=0)
		//if (AVIStreamOpenFromFile(&mVideoPavi, L"../Contents/RippleApp/Fishing/fish_scene.avi", streamtypeVIDEO, 0, OF_READ, NULL) !=0)
	{
		// An Error Occurred Opening The Stream
		MessageBox (HWND_DESKTOP, L"Failed To Open The AVI Stream", L"Error", MB_OK | MB_ICONEXCLAMATION);
	}

	AVIStreamInfo(mVideoPavi, &mVideoPsi, sizeof(mVideoPsi));						// Reads Information About The Stream Into psi
	mVideoWidth=mVideoPsi.rcFrame.right-mVideoPsi.rcFrame.left;					// Width Is Right Side Of Frame Minus Left
	mVideoHeight=mVideoPsi.rcFrame.bottom-mVideoPsi.rcFrame.top;					// Height Is Bottom Of Frame Minus Top

	mVideoLastframe=AVIStreamLength(mVideoPavi);							// The Last Frame Of The Stream

	mVideoMpf=AVIStreamSampleToTime(mVideoPavi,mVideoLastframe)/mVideoLastframe;		// Calculate Rough Milliseconds Per Frame

	mVideoBmih.biSize = sizeof (BITMAPINFOHEADER);					// Size Of The BitmapInfoHeader
	mVideoBmih.biPlanes = 1;											// Bitplanes	
	mVideoBmih.biBitCount = 24;										// Bits Format We Want (24 Bit, 3 Bytes)
	mVideoBmih.biWidth = 1024;											// Width We Want (256 Pixels)
	mVideoBmih.biHeight = 768;										// Height We Want (256 Pixels)
	mVideoBmih.biCompression = BI_RGB;								// Requested Mode = RGB

	mVideoHBitmap = CreateDIBSection (mVideoHdc, (BITMAPINFO*)(&mVideoBmih), DIB_RGB_COLORS, (void**)(&mVideoData), NULL, NULL);
	SelectObject (mVideoHdc, mVideoHBitmap);								// Select hBitmap Into Our Device Context (hdc)

	//pgf=AVIStreamGetFrameOpen(pavi, NULL);						// Create The PGETFRAME	Using Our Request Mode
	mVideoPgf=AVIStreamGetFrameOpen(mVideoPavi, PBITMAPINFOHEADER(AVIGETFRAMEF_BESTDISPLAYFMT));
	if (mVideoPgf==NULL)
	{
		// An Error Occurred Opening The Frame
		MessageBox (HWND_DESKTOP, L"Failed To Open The AVI Frame", L"Error", MB_OK | MB_ICONEXCLAMATION);
	}

	// Information For The Title Bar (Width / Height / Last Frame)
	wsprintf (title, L"NeHe's AVI Player: Width: %d, Height: %d, Frames: %d", mVideoWidth, mVideoHeight, mVideoLastframe);
}

void VideoPlayer::GrabAVIFrame(int frame)									// Grabs A Frame From The Stream
{
	LPBITMAPINFOHEADER lpbi;									// Holds The Bitmap Header Information
	lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(mVideoPgf, frame);	// Grab Data From The AVI Stream
	mVideoPdata=(char *)lpbi+lpbi->biSize+lpbi->biClrUsed * sizeof(RGBQUAD);	// Pointer To Data Returned By AVIStreamGetFrame

	// Convert Data To Requested Bitmap Format
	DrawDibDraw (mVideoHdd, mVideoHdc, 0, 0, 1024, 768, lpbi, mVideoPdata,	 0, 0, mVideoWidth, mVideoHeight, 0);

	flipIt(mVideoData);												// Swap The Red And Blue Bytes (GL Compatability)

	// Update The Texture
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 768, 0, GL_RGB, GL_UNSIGNED_BYTE, mVideoData); 
}

void VideoPlayer::CloseAVI(void)												// Properly Closes The Avi File
{
	DeleteObject(mVideoHBitmap);										// Delete The Device Dependant Bitmap Object
	DrawDibClose(mVideoHdd);											// Closes The DrawDib Device Context
	AVIStreamGetFrameClose(mVideoPgf);								// Deallocates The GetFrame Resources
	AVIStreamRelease(mVideoPavi);										// Release The Stream
	AVIFileExit();												// Release The File
}

bool VideoPlayer::Initialize ()					// Any GL Init Code & User Initialiazation Goes Here
{
	// Start Of User Initialization
	mVideoHdd = DrawDibOpen();										// Grab A Device Context For Our Dib
	glClearColor (0.0f, 0.0f, 0.0f, 0.5f);						// Black Background
	glClearDepth (1.0f);										// Depth Buffer Setup
	glDepthFunc (GL_LEQUAL);									// The Type Of Depth Testing (Less Or Equal)
	glEnable(GL_DEPTH_TEST);									// Enable Depth Testing
	glShadeModel (GL_SMOOTH);									// Select Smooth Shading
	glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);			// Set Perspective Calculations To Most Accurate


	OpenAVI(mVideoName);									// Open The AVI File
	//OpenAVI(L"cat_and_mouse.avi");									// Open The AVI File

	// Create The Texture
	glGenTextures(1, &mVideoImageID);
	glBindTexture(GL_TEXTURE_2D, mVideoImageID);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 768, 0, GL_RGB, GL_UNSIGNED_BYTE, mVideoData);
	return TRUE;												// Return TRUE (Initialization Successful)
}

void VideoPlayer::Deinitialize (void)										// Any User DeInitialization Goes Here
{
	CloseAVI();													// Close The AVI File
}

void VideoPlayer::Update (DWORD milliseconds)								// Perform Motion Updates Here
{
	mVideoNext+=milliseconds;											// Increase next Based On The Timer
	mVideoFrame=mVideoNext/mVideoMpf;												// Calculate The Current Frame


	if (mVideoFrame>=mVideoLastframe)										// Are We At Or Past The Last Frame?
	{
		mVideoFrame=0;												// Reset The Frame Back To Zero (Start Of Video)
		mVideoNext=0;													// Reset The Animation Timer (next)
	}
}

void VideoPlayer::Render (void)												// Draw Our Scene
{
	GrabAVIFrame(mVideoFrame);										// Grab A Frame From The AVI
	glEnable(GL_TEXTURE_2D);
	glPushMatrix();

	//glLoadIdentity();										// Reset The Modelview Matrix
	glBegin(GL_QUADS);										// Begin Drawing The Background (One Quad)


	glTexCoord2f(1.0f, 1.0f); glVertex3f( 1024.0f, 768.f, 0.0f);
	glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.0f,  768.f, 0.0f);
	glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.0f, 0.0f, 0.0f);
	glTexCoord2f(1.0f, 0.0f); glVertex3f( 1024.0f, 0.0f, 0.0f);

	glEnd();												// Done Drawing The Background

	glPopMatrix();
	//glFlush ();													// Flush The GL Rendering Pipeline
}